package de.seminar.lego3D;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.regex.Matcher;

import de.seminar.lego3D.fragments.DetailsFragment;
import de.seminar.lego3D.fragments.LegoBricksFragment;
import de.seminar.lego3D.fragments.SettingsFragment;
import de.seminar.lego3D.helper.TransparentPanel;
import de.seminar.lego3D.qrCode.IntentIntegrator;
import de.seminar.lego3D.qrCode.IntentResult;

import android.app.Activity;
import android.app.FragmentTransaction;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.PopupWindow;
import android.widget.TextView;
import android.widget.Toast;

/**
 * The main activity, that handles the main logic of the application.
 * @author Christian Lander
 *
 */
public class Lego3DActivity extends Activity {

	/** to store the color history **/
	private static SharedPreferences colorValues;

	/** the colors **/
	public static HashMap<String, Integer> colors;

	/** context of this activity **/
	private Context mContext;

	/** popup window shown by clicking on connect **/
	private PopupWindow popup;

	/** connector to the server **/
	public static ClientConnector connector;

	/**
	 * Handler to receive callback from receiver thread when connection is
	 * established
	 **/
	private final Handler mCommunicationCallbackHandler = new Handler() {

		@Override
		public void handleMessage(final Message msg) {
			super.handleMessage(msg);
			final Bundle bundle = msg.getData();
			if (bundle != null) {
				if (bundle.getBoolean(Constants.SUCCESSFUL)) {
					Toast.makeText(mContext, "Connection established",
							Toast.LENGTH_SHORT).show();
					connector.killReceiver();
//					DetailsFragment settingsFragment = (DetailsFragment) getFragmentManager()
//							.findFragmentById(R.id.details_frag);
//					if (settingsFragment != null
//							&& Constants.CUR_FRAG == 2) {
//						((SettingsFragment) settingsFragment).updateImage();
//					}
				}
				//updates the image, if necessary (if this fragment is visible), showing if we are connected
				DetailsFragment settingsFragment = (DetailsFragment) getFragmentManager()
						.findFragmentById(R.id.details_frag);
				if (settingsFragment != null
						&& Constants.CUR_FRAG == 2) {
					((SettingsFragment) settingsFragment).updateImage();
				}
			}
		}
	};

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);

		mContext = this;

		// restore color values
		colorValues = getSharedPreferences(Constants.COLOR_HISTORY,
				Context.MODE_PRIVATE);

		// write the default colors, only if there is nothing
		if (colorValues.getAll().isEmpty()) {
			loadDefaultColors();
		}

		// get the colors
		colors = (HashMap<String, Integer>) colorValues.getAll();

		restoreColorList();

		for (String s : colors.keySet()) {
			Log.v("colors", s + " - " + colors.get(s));
		}

		// get the list view
		TransparentPanel panel = (TransparentPanel) LayoutInflater.from(this)
				.inflate(R.layout.popup_list, null, false);
		ListView lv = (ListView) panel.findViewById(R.id.list);
		lv.setAdapter(new MyListAdapter(mContext));
		lv.setOnItemClickListener(new OnItemClickListener() {

			@Override
			public void onItemClick(AdapterView<?> av, View v, int pos, long id) {
				switch (pos) {
				case 0:
					//does the QR code detection
					popup.dismiss();
					doQRCodeScan();

					break;
				case 1:
					//opens the third fragment to type in the IP of the server
					popup.dismiss();
					DetailsFragment settingsFragment = (DetailsFragment) getFragmentManager()
							.findFragmentById(R.id.details_frag);
					if (settingsFragment == null
							|| settingsFragment.getShownIndex() != 2) {
						// Make new fragment to show this selection.
						settingsFragment = SettingsFragment.newInstance(2);

						// Execute a transaction, replacing any existing
						// fragment
						// with this one inside the frame.
						FragmentTransaction ft = getFragmentManager()
								.beginTransaction();
						ft.replace(R.id.details_frag, settingsFragment);
						ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
						ft.commit();
					}
					Constants.CUR_FRAG = 2;
					break;
				}
			}
		});

		connector = new ClientConnector(mContext, mCommunicationCallbackHandler);

		// init the popup with the list view
		popup = new PopupWindow(panel, ViewGroup.LayoutParams.WRAP_CONTENT,
				ViewGroup.LayoutParams.WRAP_CONTENT, true);
	}

	/**
	 * Causes to do a QR Code scan via Intent. (see at
	 * http://code.google.com/p/zxing/wiki/ScanningViaIntent)
	 */
	private void doQRCodeScan() {
		IntentIntegrator
				.initiateScan(
						this,
						"Install Barcode Scanner?",
						"This application requires Barcode Scanner. Would you like to install it?",
						"Yes", "No", "QR_CODE");
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.main_menu, menu);
		return super.onCreateOptionsMenu(menu);
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.menuConnect:
			//causes to show the popup where the user can choose between QR code detection and manually IP input
			popup.showAtLocation(getCurrentFocus(), Gravity.CENTER, 0, 0);
			return true;
		default:
			return super.onOptionsItemSelected(item);
		}
	}

	@Override
	protected void onStop() {
		storeColors(Constants.colors);
		super.onStop();
	}

	@Override
	protected void onDestroy() {
		connector.sendDisconnect();
		connector.kill();
		super.onDestroy();
	}

	/**
	 * Handles the result of the QR Code scan, and causes the client connector to connect, if a valid IP address was decoded.
	 */
	public void onActivityResult(int requestCode, int resultCode, Intent intent) {
		IntentResult scanResult = IntentIntegrator.parseActivityResult(
				requestCode, resultCode, intent);
		if (scanResult != null) {
			String content = scanResult.getContents();
			if (content != null) {
				Matcher matcher = Constants.pattern.matcher(content);
				if (matcher.matches()) {
					Constants.HOST_IP = content;
					if (!connector.connected()) {
						connector.start(Constants.HOST_IP);
					} else {
						Toast.makeText(mContext, "Already connected",
								Toast.LENGTH_SHORT).show();
					}
				} else {
					Toast.makeText(mContext, "Invalid IP address",
							Toast.LENGTH_SHORT).show();
				}
			} else {
				Toast.makeText(mContext, "No information decoded",
						Toast.LENGTH_SHORT).show();
			}
		} else {
			Toast.makeText(mContext, "QR Code detection not successful",
					Toast.LENGTH_SHORT).show();
		}
	}

	/**
	 * Loads the default color set, and stores it.
	 */
	private void loadDefaultColors() {
		SharedPreferences.Editor colorValuesEditor = colorValues.edit();

		for (String s : Constants.defaultColors.keySet()) {
			colorValuesEditor.putInt(s, Constants.defaultColors.get(s));
		}

		colorValuesEditor.apply();
	}

	/**
	 * Stores the colors in the preferences.
	 */
	private void storeColors(ArrayList<Integer> colsTemp) {

		SharedPreferences.Editor colorValuesEditor = colorValues.edit();

		colorValuesEditor.clear();
		colorValuesEditor.apply();

		for (Integer i : colsTemp) {
			colorValuesEditor.putInt(i + "", i);
		}

		colorValuesEditor.apply();
	}

	/**
	 * Restores the current color list.
	 */
	private void restoreColorList() {
		Constants.colors = new ArrayList<Integer>(colors.values());
	}

	/**
	 * Sends the information of the current brick over the socket to the server.
	 * 
	 * @param sfNormal
	 */
	public void onClickSend(View sfNormal) {
		DetailsFragment legoFragment = (DetailsFragment) getFragmentManager().findFragmentById(R.id.details_frag);
		if (Constants.CURRENT_LEGO == null) {
			((LegoBricksFragment) legoFragment).startAnimation(true);
			Toast.makeText(mContext,
					"Please choose a brick to send.",
					Toast.LENGTH_SHORT).show();
		} else {
			((LegoBricksFragment) legoFragment).startAnimation(false);
			connector.sendBirckInformation(Constants.CURRENT_LEGO);
		}
	}

	/**
	 * List Adapter for the popup view showing the possibilities of connection.
	 * @author christian
	 *
	 */
	private class MyListAdapter extends BaseAdapter implements ListAdapter {

		/** context of the main activity **/
		private Context context;

		/**
		 * Creates a new adapter.
		 * 
		 * @param ctx
		 */
		public MyListAdapter(Context ctx) {
			context = ctx;
		}

		@Override
		public int getCount() {
			return 2;
		}

		@Override
		public Object getItem(int position) {
			return Constants.spinnerTags[position];
		}

		@Override
		public long getItemId(int position) {
			return position;
		}

		@Override
		public View getView(int position, View convertView, ViewGroup parent) {
			View v = LayoutInflater.from(context).inflate(R.layout.list_item,
					null, false);
			ImageView img = (ImageView) v.findViewById(R.id.item_image);
			img.setImageResource(Constants.spinner_imgs[position]);
			TextView tv = (TextView) v.findViewById(R.id.item_text);
			tv.setText(Constants.spinnerTags[position]);
			return v;
		}
	}
}